/**
 *
 * Licensed Property to China UnionPay Co., Ltd.
 * 
 * (C) Copyright of China UnionPay Co., Ltd. 2010
 *     All Rights Reserved.
 *
 * 
 * Modification History:
 * =============================================================================
 *   Author         Date          Description
 *   ------------ ---------- ---------------------------------------------------
 *   xshu       2014-05-28       证书工具类.
 * =============================================================================
 */
package com.ny.zmb.openapi.util;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Enumeration;

public class CertUtil {
	/** 证书容器. */
	private static KeyStore keyStore = null;

	/** 验证签名证书. */
	private static Certificate validateCert = null;

	/** 验证签名证书. KEYSTORE_TYPE-PKCS12 */
	private static final String KEYSTORE_TYPE = "PKCS12";

	/** 验证签名证书. CERTFACTORY_TYPE-PKCS12 */
	private static final String  CERTFACTORY_TYPE= "X.509";

	/**
	 * 加载签名证书
	 */
	public static KeyStore initSignCert(String pfxPath,String pfxPwd) throws Exception {
		if (null != keyStore) {
			keyStore = null;
		}
		try {
			// 默认存放的文件夹路径
			keyStore = getKeyInfo(pfxPath,pfxPwd, KEYSTORE_TYPE);
		} catch (IOException e) {
			e.printStackTrace();
			throw e;
		}
		return keyStore;
	}
	/**
	 * 将证书文件读取为证书存储对象
	 *
	 * @param pfxkeyfile
	 *            证书文件名
	 * @param keypwd
	 *            证书密码
	 * @param type
	 *            证书类型 ,以.pfx结尾用PKCS12
	 * @return 证书对象
	 * @throws IOException
	 */
	public static KeyStore getKeyInfo(String pfxkeyfile,String keypwd,String type) throws Exception {
		FileInputStream fis = null;
		try {

			KeyStore ks = null;
			ks = KeyStore.getInstance(type);
			fis = new FileInputStream(pfxkeyfile);
			char[] nPassword = null;
			nPassword = null == keypwd || "".equals(keypwd.trim()) ? null: keypwd.toCharArray();
			if (null != ks){
				ks.load(fis, nPassword);
			}
			return ks;
		} catch (Exception e) {
			throw e;
		}finally{
			if(null!=fis){
				fis.close();
			}
		}
	}

	/**
	 * 获取签名证书私钥（单证书）
	 */
	public static PrivateKey getSignCertPrivateKey(String pfxPath,String pfxPwd)throws Exception {
		if(keyStore == null){
			keyStore = initSignCert(pfxPath,pfxPwd);
		}
		Enumeration<String> aliasenum = keyStore.aliases();
		String keyAlias = null;
		if (aliasenum.hasMoreElements()) {
			keyAlias = aliasenum.nextElement();
		}
		PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, pfxPwd.toCharArray());
		return privateKey;
	}

	/**
	 * 从指定目录书路径获取Certificate对象
	 * @return
	 */
	public static Certificate initValidateCertFromDir(String crtPath) throws Exception {
		CertificateFactory cf = null;
		FileInputStream in = null;
		try {
			cf = CertificateFactory.getInstance(CERTFACTORY_TYPE);
			in = new FileInputStream(crtPath);
			validateCert = cf.generateCertificate(in);
		} catch (CertificateException e) {
			throw  e;
		} catch (FileNotFoundException e) {
			throw  e;
		} finally {
			if (null != in) {
				try {
					in.close();
				} catch (IOException e) {
					throw  e;
				}
			}
		}
		return validateCert;
	}

	/**
	 * 根据证书路径获取Certificate对象
	 */
	public static Certificate getValidateCert(String crtPath) throws Exception {
		System.out.println("Cert starts loading...[certPath is:"+crtPath+"]");
		if(validateCert != null){
			System.out.println("cert is already exists,don't need to load it");
			return validateCert;
		}
		return initValidateCertFromDir(crtPath);
	}

	/**
	 * 根据公钥字符串获取PublicKey对象
	 * @return
	 */
	public static PublicKey getPubKeyObj(String pubKey)throws Exception {
		java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec(new BASE64Decoder().decodeBuffer(pubKey));
		// RSA对称加密算法
		KeyFactory keyFactory;
		keyFactory = KeyFactory.getInstance("RSA");
		// 取公钥匙对象
		PublicKey publicKey = keyFactory.generatePublic(bobPubKeySpec);
		return publicKey;
	}

	/**
	 * 根据私钥字符串获取PrivateKey对象
	 * @return
	 */
	public static PrivateKey getPriKeyObj(String priKeyStr) throws Exception {
		PrivateKey privateKey = null;
		PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(new BASE64Decoder().decodeBuffer(priKeyStr));
		KeyFactory keyf = KeyFactory.getInstance("RSA");
		privateKey = keyf.generatePrivate(priPKCS8);
		return privateKey;
	}

	/**
	 * 获取私钥字符串根据私钥证书和密码
	 */
	public static String getPrivateKeyInfo(String privKeyFilePath,String privKeyPswd) throws Exception {
		KeyStore keyStore = KeyStore.getInstance( KEYSTORE_TYPE);
		FileInputStream fileInputStream = new FileInputStream(privKeyFilePath);
		char[] nPassword = null;
		if ((privKeyPswd == null) || privKeyPswd.trim().equals( "")) {
			nPassword = null;
		} else {
			nPassword = privKeyPswd.toCharArray();
		}
		keyStore.load(fileInputStream, nPassword);
		fileInputStream.close();
		Enumeration<String> enumeration = keyStore.aliases();
		String keyAlias ="";
		if (enumeration.hasMoreElements()) {
			keyAlias = (String) enumeration.nextElement();
		}
		PrivateKey prikey = (PrivateKey) keyStore.getKey(keyAlias, nPassword);
		return new BASE64Encoder().encode(prikey.getEncoded());
	}

	/**
	 * 获取公钥字符串 根据公钥证书
	 */
	public static String getPublicKeyInfo(String publicKeyPath) throws Exception {
		//获取X.509对象工厂
		CertificateFactory cf = CertificateFactory.getInstance(CERTFACTORY_TYPE);
		//通过文件流读取证书文件
		X509Certificate cert = (X509Certificate)cf.generateCertificate(new FileInputStream(publicKeyPath));
		//获取公钥对象
		PublicKey publicKey = cert.getPublicKey();
		return new BASE64Encoder().encode(publicKey.getEncoded());
	}
}
